#include "sinet.h"

static int sock;

static uint16_t num_to_fd[MAX_PLAYERS];

fd_set master;
int max_fd = 0;
uint16_t num_clients = 2;

extern snake_t players[MAX_PLAYERS];
extern uint8_t is_alive[MAX_PLAYERS];
extern uint16_t alive_snakes;
extern FILE *log_file;
extern node_t *fruit_list;
extern node_t *last_list;

void init_server(const struct sockaddr_in *addr)
{
    int optval = 1;

    sock = Socket(AF_INET, SOCK_STREAM, 0);
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
    
    Bind(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
    Listen(sock, num_clients);
}


void wait_clients()
{
    struct sockaddr_in client;
    socklen_t addr_len;
    int new_fd;

    FD_ZERO(&master);

    fprintf(log_file, "Waiting %d clients connection...\n\n", num_clients);

    addr_len = sizeof(client);
    for (uint16_t connected = 0; connected < num_clients; ++connected){
        new_fd = Accept(sock, (struct sockaddr*)&client, &addr_len);

        num_to_fd[connected] = new_fd;

        max_fd = MAX(new_fd, max_fd);
        
        FD_SET(new_fd, &master);

        fprintf(log_file, "Client %d connected from %s:%d\n", 
                connected+1, inet_ntoa(client.sin_addr), ntohs(client.sin_port));
    }

    fprintf(log_file, "\n");
}


void send_start_snakes(int fd)
{
    for (uint16_t i = 0; i < num_clients; ++i)
    {
        // Send(fd, players+i, sizeof(snake_t), 0);
        Send(fd, players+i, 3, 0);
        Send(fd, players[i].body, players[i].len*sizeof(crd_t), 0);
    }
}


void send_init_mess(const struct timespec *timesp, uint16_t fr_d, 
        uint16_t fsx, uint16_t fsy)
{
    init_mess_t init_mess;
    
    init_mess.magic = 0x30;
    init_mess.timestamp = *timesp; 
    init_mess.frame_delay = fr_d;
    init_mess.field_size_x = fsx;
    init_mess.field_size_y = fsy;
    init_mess.n_players = num_clients;
    
    fprintf(log_file, "Size of field: %d x %d\n", fsx, fsy);

    for (uint16_t i = 0; i < num_clients; ++i)
    {
        init_mess.my_number = i;
        Send(num_to_fd[i], &init_mess, sizeof(init_mess_t), 0);
        send_start_snakes(num_to_fd[i]);
    }
}


void send_init_fruit(uint16_t fx, uint16_t fy)
{
    for (int i = 0; i < MAX_FRUIT; ++i)
    {
        spawn_fruit(fx, fy);
        send_fruit();
    }
}


uint16_t fd2num(uint16_t fd)
{
    for (uint16_t i = 0; i < num_clients; ++i)
    {
        if (num_to_fd[i] == fd)
            return i;
    }

    return -1;
}


void send_snakes()
{
    uint8_t magic = 0x50;
    for (uint16_t i = 0; i < num_clients; ++i)
    {
        if (!is_alive[i]) continue;

        Send(num_to_fd[i], &magic, 1, 0);
        Send(num_to_fd[i], &alive_snakes, 2, 0);
        for (uint16_t j = 0; j < num_clients; ++j)
        {
            if (!is_alive[j]) continue;
            
            Send(num_to_fd[i], &j, 2, 0);
            Send(num_to_fd[i], players+j, 3, 0);
            Send(num_to_fd[i], players[j].body, players[j].len*sizeof(crd_t), 0); 
        }
    }
}


void dead(uint16_t num)
{
    uint8_t magic = 0xff;
    uint16_t place = 0;
    
    for (uint16_t i = 0; i < num_clients; ++i)
    {
        place += is_alive[i];
    }

    Send(num_to_fd[num], &magic, 1, 0);
    Send(num_to_fd[num], &place, 2, 0);

    close(num_to_fd[num]);
    is_alive[num] = 0;
    alive_snakes -= 1;
    FD_CLR(num_to_fd[num], &master);
}


void send_fruit()
{
    uint8_t magic = 0xb0;
    for (int i = 0; i < num_clients; ++i)
    {
        if (!is_alive[i]) continue;

        Send(num_to_fd[i], &magic, 1, 0);

        Send(num_to_fd[i], ((crd_t *)(last_list->data)), 4, 0);   
    }
}
